package com.me.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.me.bean.ClientMessBean;
import com.me.bean.ServerMessBean;
import com.me.contast.MessFlag;
import com.me.utils.JsonUtil;
import com.me.utils.StringRegex;



/*
 * 
 * 
 * 
 * 消息收发应采用json或其他格式，方便处理。。。屏蔽，定义命令格式等
 * 
 * 
 * 
 *
 */

 /**
 * 线程会越来越多？？？应该不会。。。bug
 * @author Yue
 * 
 */
public class MiniTcpServer implements TcpServer{

	private HashMap<String, Socket> socketMap ;
	private HashMap<String,Service> serviceMap ; 


	private ExecutorService mExecutorService = null; //thread pool
	private static final int PRE_PORT = 2537;
	private int port = PRE_PORT;
	private ServerSocket serverSocket;

	public MiniTcpServer() {
		socketMap = new HashMap<>();
		serviceMap = new HashMap<>();
	}

	@Override
	public void soon() {

		try {
			System.out.println("输入端口号：");
			BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
			String str = buffer.readLine();
			if (StringRegex.isNumber(str)) {
				port = Integer.parseInt(str);				
			}else {
				port = PRE_PORT;
			}
			serverSocket = new ServerSocket(port);

			InetAddress address = InetAddress.getLocalHost();//获取的是本地的IP地址 //PC-20140317PXKX/192.168.0.121
			String ipAddress = address.getHostAddress();

			mExecutorService = Executors.newCachedThreadPool();  //create a thread pool
			System.out.println("服务器已在"+ipAddress+":"+serverSocket.getLocalPort()+"启动...");
			
			Socket client = null;
			while(true) {
				client = serverSocket.accept();				

				String clientAddress = client.getInetAddress().getHostAddress();
				socketMap.put(clientAddress, client);

				if (serviceMap.containsKey(clientAddress)) {
					serviceMap.get(clientAddress).close();//多ci一举，好像关不掉关不掉关不掉关不掉关不掉关不掉关不掉关不掉关不掉关不掉关不掉关不掉
				}

				Service service = new Service(client);
				serviceMap.put(clientAddress, service);

				//线程越来越多，要爆掉
				mExecutorService.execute(service);
				
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	class Service implements Runnable {
		private Socket socket;
		private BufferedReader in = null;
		private String clientAddress;

		private boolean closeFlag = false;
		public void close() {
			closeFlag = true;
			if (socket!=null) {
				try {
					socket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
		public Service(Socket socket) {
			clientAddress = socket.getInetAddress().getHostAddress();

			this.socket = socket;
			try {

				in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));

				System.out.println("客户端地址："+clientAddress +"   当前连接数："+socketMap.size());
				
				ServerMessBean serverMessBean = new ServerMessBean(System.currentTimeMillis(),"服务器",null,"连接成功",MessFlag.FLAG_MAIN,null,"今天天气良好");
				this.sendMessToClient(serverMessBean, clientAddress);

			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	
		@Override
		public void run() {

			try {
				while(!closeFlag) {
					String receiveMsgJson = "{}";
					
					if(in.ready() && ((receiveMsgJson=in.readLine()) != null)) {
						System.out.println("收到： "+receiveMsgJson);
						//当客户端发送的信息为：exit时，关闭连接
						
						ClientMessBean clientMessBean = JsonUtil.getClientMessBean(receiveMsgJson) ;
						int messFlag = clientMessBean.getMessFlag();
						String name = clientMessBean.getName();
						String mess = clientMessBean.getMess();
						
						
						//是正文消息
						if (messFlag == MessFlag.FLAG_MAIN) {
							ServerMessBean serverCallBack = new ServerMessBean(System.currentTimeMillis(),"服务器",null,"正在为您分发消息",MessFlag.FLAG_MAIN,null,"晴");
							this.sendMessToClient(serverCallBack, this.clientAddress);
							
							ServerMessBean serverNotify = new ServerMessBean(System.currentTimeMillis(),name,null,mess,MessFlag.FLAG_MAIN,null,"风和日丽");
							this.sendMessToClientsExcept(serverNotify, clientAddress);
						
						}
						//发来的消息是命令
						else if (clientMessBean.getMessFlag() == MessFlag.FLAG_CMD) {
							System.out.println("收到命令："+mess);
							if(mess.equals("exit")) {
								socketMap.remove(this.clientAddress);

								in.close();
								socket.close();

								System.out.println("客户端： " + this.clientAddress + " 退出连接，当前连接数：" + socketMap.size());
								
								
								//通知其他所有连接，xxx下线
								ServerMessBean serverMessBean = new ServerMessBean(System.currentTimeMillis(),"服务器",null,name+"退出连接",MessFlag.FLAG_MAIN,null,"黑云翻墨");
								this.sendMessToEveryClient(serverMessBean);
								break;
								//接收客户端发过来的信息msg，然后发送给客户端。
							}
							else {
								System.out.println("无法执行此命令...");
								ServerMessBean serverMessBean = new ServerMessBean(System.currentTimeMillis(),"服务器",null,"无法执行此命令...",MessFlag.FLAG_MAIN,null,"黑云翻墨");								
								this.sendMessToClient(serverMessBean, clientAddress);
							}
							
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	
		/**
		 * 循环遍历客户端集合，给每个客户端都发送信息。
		 */
		public void sendMessToEveryClient(ServerMessBean serverMessBean) {
			System.out.println("即将发送全局消息---------->>");
			sendMessToClients(serverMessBean, socketMap);
		}
		
		/**
		 * 发送消息过去，除了某个地址
		 * @param mess
		 * @param adress
		 */
		public void sendMessToClientsExcept(ServerMessBean serverMessBean ,String adress) {
			HashMap<String, Socket> sendMap = (HashMap<String, Socket>) socketMap.clone();//HashMap是浅拷贝
			sendMap.remove(adress);
			sendMessToClients(serverMessBean, sendMap);
			
		}
		/**
		 * 发送消息过去，除了某些地址
		 * @param mess
		 * @param adress
		 */
		public void sendMessToClientsExcept(ServerMessBean serverMessBean ,String[] adress) {
			System.out.println("---------->>");
			HashMap<String, Socket> sendMap = (HashMap<String, Socket>) socketMap.clone();//HashMap是浅拷贝
			for (int i = 0; i < adress.length; i++) {
				sendMap.remove(adress[i]);
			}
			
			sendMessToClients(serverMessBean, sendMap);
		}
		
		/**
		 * 发消息到指定客户端
		 * @param mess
		 * @param address
		 */
		public void sendMessToClient(ServerMessBean serverMessBean,String address) {
			
			String mess = JsonUtil.getJsonString(serverMessBean);

			System.out.println("发送："+serverMessBean+" 到"+address);
			
			Socket socket = socketMap.get(address);
			PrintWriter printWriter = null;
			
			try {
				if (socket != null) {
					OutputStream os = socket.getOutputStream();
					OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
					BufferedWriter bw = new BufferedWriter(osw);
					printWriter = new PrintWriter(bw);
					printWriter.println(mess);
					printWriter.flush();

				} 
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		/**
		 * 发消息到很多客户端
		 * @param mess
		 * @param clientMap
		 */
		public void sendMessToClients(ServerMessBean serverMessBean,Map<String, Socket> clientMap) {
			Iterator<String> iterator= clientMap.keySet().iterator();

			String mess = JsonUtil.getJsonString(serverMessBean);

			while (iterator.hasNext()) {
				String address = iterator.next();
				Socket socket = clientMap.get(address);
				
				PrintWriter printWriter = null;

				try {
					if (socket != null) {
						OutputStream os = socket.getOutputStream();
						OutputStreamWriter osw = new OutputStreamWriter(os,"utf-8");
						BufferedWriter bw = new BufferedWriter(osw);
						printWriter = new PrintWriter(bw);
						printWriter.println(mess);
						printWriter.flush();
						System.out.println("发送："+mess+"  到   "+address);
					} 
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}    

}

